<?php 
function self( ){
    $stack_list = debug_backtrace();
    for ($i=0; $i < count($stack_list); $i++) {
        $stack = $stack_list[$i];
        if (isset($stack['object']) && $stack['object'] instanceof Generator) {
            return $stack['object'];
        }
    }
    throw new Exception("Error Processing Request", 1); 
}

function spawn($fn){
    $gen = $fn(); 
    $GLOBALS[$key='___'.microtime() ]=new class($gen,$key){
        function __construct($gen,$key){
            $this->gen = $gen;
            $this->key=$key;
        }
        function __destruct(){  
            $this->gen->current();  
            if(isset($GLOBALS[$this->key])){
                unset($GLOBALS[$this->key]); 
            }
        }
    };
    return $gen;
}
function defer($fn){
    $GLOBALS[$key = '___'.microtime() ]=new class($fn,$key){
        function __construct($fn,$key){
            $this->fn = $fn;
            $this->key=$key;
        }
        function __destruct(){ 
            ($this->fn)();  
            if(isset($GLOBALS[$this->key])){
                unset($GLOBALS[$this->key]); 
            }
        }
    }; 
} 
function receive(){

}
function send($gen,$str){
    defer(function()use($b){
        $b->send('toB'); 
    });  
}
spawn(function(){
    $a = self(); 
        
    $b = spawn(function()use($a) {  
        while (1){   
            send($a,'toA');   
            echo yield from receive(); 
        }
    });

    while (1){    
        send($b,'toB'); 
        echo yield from receive();  
    } 
});

 